/**
    @file pixelobj.cpp
    @brief Game object
*/
#include "pixel/pixelobj.hpp"
#include "lua/lua_pixelobj.hpp"
#include "lua/lua_pixelnode.hpp"
#include "lua/lua_pixelplayer.hpp"

pm3::PIXELOBJ *pm3::lua::g_active_obj = NULL;

pm3::PIXELOBJ::PIXELOBJ() {
    m_directions = 0;

    m_instance_script = "node = get_active_node();\n";
}

pm3::PIXELOBJ::~PIXELOBJ() {
    unload();
}

pm3::PIXELOBJ& pm3::PIXELOBJ::operator=( const pm3::PIXELOBJ &r_obj ) {
    m_color = r_obj.m_color;
    m_directions = r_obj.m_directions;
    m_tags = r_obj.m_tags;

    return *this;
}

void pm3::PIXELOBJ::unload() {
    m_directions = 0;

    pm3::lua::g_active_obj = NULL;
}

void pm3::PIXELOBJ::bind() {
    tolua_ogre_vector3_open( m_lua_state );
    tolua_objscript_open( m_lua_state );
    tolua_nodescript_open( m_lua_state );
    tolua_playerscript_open( m_lua_state );
}

void pm3::PIXELOBJ::update() {
    // Set the active object
    pm3::lua::g_active_obj = this;
    // Proceed with the default luascript update
    pm3::LUA_SCRIPTED::update();
}

void pm3::PIXELOBJ::instance_setup( PIXELNODE *p_node, const Ogre::Vector3 &r_grid_pos ) {
    LOGGER *log = LOGGER::getSingletonPtr();

    if (!p_node) {
        if (log)
            log->report( "Pixel", "E: Null pointer passed to pixel object instance setup\n" );
        return;
    }

    // Set the active node
    pm3::lua::g_active_node = p_node;
    // Set the active object
    pm3::lua::g_active_obj = this;

    // Lua online and worldscript loaded?
    if (m_lua_state) {
        // Push the function name
		lua_pushstring( m_lua_state, "instance" );
        // Push the function as global["instance"]
		lua_gettable( m_lua_state, LUA_GLOBALSINDEX );
		// Push arguments
		lua_pushnumber( m_lua_state, r_grid_pos.z );
		lua_pushnumber( m_lua_state, r_grid_pos.x );
		lua_pushnumber( m_lua_state, r_grid_pos.y );
		// Call the function
		if (lua_pcall( m_lua_state, 3, 0, 0 ) != 0) {
            if (log)
                log->report( "Lua", "E: Lua instance callback error in file \"%s\": \"%s\"\n", 
                             m_script_path.c_str(), lua_tostring( m_lua_state, lua_gettop( m_lua_state ) ) );
        }
    } else {
        if (log)
            log->report( "Lua", "E: Invalid Lua state\n" );
    }
}

void pm3::PIXELOBJ::enter_room( int i_layer, int i_x, int i_y ) {
    LOGGER *log = LOGGER::getSingletonPtr();
    std::string error;

    // Set the active object
    pm3::lua::g_active_obj = this;

    // Lua online and worldscript loaded?
    if (m_lua_state) {
        // Push the function name
		lua_pushstring( m_lua_state, "player_entered" );
        // Push the function as global["player_entered"]
		lua_gettable( m_lua_state, LUA_GLOBALSINDEX );
		// Push arguments
		lua_pushnumber( m_lua_state, i_layer );
		lua_pushnumber( m_lua_state, i_x );
		lua_pushnumber( m_lua_state, i_y );
		// Call the function
		if (lua_pcall( m_lua_state, 3, 0, 0 ) != 0) {
            // Fetch the error
            error = lua_tostring( m_lua_state, lua_gettop( m_lua_state ) );
            // Don't report errors like "attempt to call a nil value"
            if (log && error != "attempt to call a nil value")
                log->report( "Lua", "E: Lua update callback error in file \"%s\": \"%s\"\n", 
                             m_script_path.c_str(), error.c_str() );
        }
    } else {
        if (log)
            log->report( "Lua", "E: Invalid Lua state\n" );
    }
}

std::string pm3::PIXELOBJ::save_script( const std::string &r_path ) {
    std::string script;

    if (r_path.empty())
        return "";

    std::string path = get_directory() + r_path;

    FILE *fo = fopen( path.c_str(), "wt" );

    if (fo) {
        fprintf( fo, "-- PMaz3 objectscript\n" );

        // Write global script
        if (!m_global_script.empty())
            fprintf( fo, "%s\n", m_global_script.c_str() );

        // Write instance callback
        if (!m_instance_script.empty())
            fprintf( fo, "\nfunction instance()\n%send\n", m_instance_script.c_str() );

        // Write player_entered callback
        if (!m_player_entered_script.empty())
            fprintf( fo, "\nfunction player_entered( i_layer, i_x, i_y )\n%send\n", m_player_entered_script.c_str() );

        fprintf( fo, "\n" );

        // Mark the script as saved
        m_unsaved = false;

        fclose( fo );

        return path;
    }

    return "";
}

void pm3::PIXELOBJ::update_script_snippets() {
    m_instance_script = get_callback_contents( "instance" );
    m_player_entered_script = get_callback_contents( "player_entered" );

    //! \todo Add support for extracting the global script
}

